#!/bin/bash
# @configure_input@
#
# Script to generate a chroot environment from a docker image
#
# The space required is dependent on the docker image you use.
# Dependencies: curl, tar, kernel 3.10; xzutils?
#
# Part of the DOMjudge Programming Contest Jury System and licensed
# under the GNU GPL. See README and COPYING for details.

# Abort when a single command fails(or uninitialized variable is accessed):
set -eu

# Default directory where to build the chroot tree:
CHROOTDIR="@judgehost_chrootdir@"

usage()
{
	cat <<EOF
Usage: $0 [options]...
Creates a chroot environment from a docker image

Options:
  -i <image>:<tag>   Docker image to build chroot from
  -d <dir>           Directory where to build the chroot environment.
  -y                 Force overwriting the chroot dir and downloading debootstrap.
  -h                 Display this help.

This script must be run as root, <chrootdir> is the non-existing
target location of the chroot (unless '-y' is specified). The
default chrootdir is '@judgehost_chrootdir@'.

EOF
}

error()
{
    echo "Error: $*"
    echo
    usage
    exit 1
}

# Read command-line parameters:
SHOWHELP=0
FORCEYES=0
IMAGE=""
while getopts 'i:d:yh' OPT ; do
	case $OPT in
		i) IMAGE=$OPTARG ;;
		d) CHROOTDIR=$OPTARG ;;
		y) FORCEYES=1 ;;
		h) SHOWHELP=1 ;;
		\?) error "Could not parse options." ;;
	esac
done
shift $((OPTIND-1))
if [ $# -gt 0 ]; then
	error "Additional arguments specified."
fi

if [ "$SHOWHELP" -eq "1" ]; then
	usage
	exit 0
fi

if [ "$(id -u)" != 0 ]; then
    echo "Warning: you probably need to run this program as root."
fi

[ -z "$CHROOTDIR" ] && error "No chroot directory given or default known."
[ -z "$IMAGE" ] && error "No docker image specified(-i image:tag)"

if [ -e "$CHROOTDIR" ]; then
	if [ ! "$FORCEYES" ]; then
		printf "'%s' already exists. Remove? (y/N) " "$CHROOTDIR"
		read -r yn
		if [ "$yn" != "y" ] && [ "$yn" != "Y" ]; then
			error "Chrootdir already exists, exiting."
		fi
	fi
	cleanup
	rm -rf "$CHROOTDIR"
fi

mkdir -p "$CHROOTDIR"
cd "$CHROOTDIR"
CHROOTDIR="$PWD"


WORKDIR="$(mktemp -d)"
DOCKER_BINARY_PATH="$WORKDIR/docker-binary"
mkdir "$DOCKER_BINARY_PATH"

echo "Downloading and extracting docker binaries"
curl https://download.docker.com/linux/static/stable/x86_64/docker-18.06.1-ce.tgz | tar -C $DOCKER_BINARY_PATH --strip-components=1 -xzf -
echo "{}" > "$WORKDIR/docker-config.json"

echo "Launching docker daemon so we can download/extract files"
export PATH="$DOCKER_BINARY_PATH:$PATH"
$DOCKER_BINARY_PATH/dockerd \
  --data-root $WORKDIR/docker-data \
  --exec-root $WORKDIR/docker-exec \
  --pidfile $WORKDIR/docker.pid \
  --config-file $WORKDIR/docker-config.json \
  --host unix://$WORKDIR/docker.sock \
  --group root \
  --iptables=false \
  --bridge=none &

DOCKER="$DOCKER_BINARY_PATH/docker -H unix://$WORKDIR/docker.sock"

echo "Running docker to download/extract the contents of an image"
container="$($DOCKER create $IMAGE)"
$DOCKER export "$container" | tar -C $CHROOTDIR -xf -

echo "Shutting down docker daemon"
kill -9 "$(cat $WORKDIR/docker.pid)"

# Wait a bit to make sure all files are closed and we can umount
sleep 1

# Unmount anything mounted there(docker leaves some things behind)
awk "\$2 ~ \"^$WORKDIR\" { print \$2 }" /proc/mounts | while read -r mountpoint; do
    umount $mountpoint
done

rm -rf "$WORKDIR" || true


# Do some final domjudge specific set up of the chroot
rm -f "$CHROOTDIR/etc/resolv.conf"
cp /etc/resolv.conf /etc/hosts /etc/hostname "$CHROOTDIR/etc" || true
cp /etc/ssl/certs/ca-certificates.crt "$CHROOTDIR/etc/ssl/certs/" || true
cp -r /usr/share/ca-certificates/* "$CHROOTDIR/usr/share/ca-certificates" || true
cp -r /usr/local/share/ca-certificates/* "$CHROOTDIR/usr/local/share/ca-certificates" || true

# Disable root account
sed -i "s/^root::/root:*:/" "$CHROOTDIR/etc/shadow"

# Create a dummy file to test that in the judging environment no
# access to group root readable files is available:
echo "This file should not be readable inside the judging environment!" \
	> "$CHROOTDIR/etc/root-permission-test.txt"
chmod 0640 "$CHROOTDIR/etc/root-permission-test.txt"


echo "Done building chroot in $CHROOTDIR"
exit 0
